// phalanx add_move_reference.hpp.cu header file

// Copyright (c) 2010 - 2011 Kohei Takahashi (Flast).
// Distributed under the MIT license. for more detail see COPYING.

#ifndef IG_PHALANX_MOVE_DETAIL_ADD_MOVE_REFERENCE_HPP_CU_ONCE_
#define IG_PHALANX_MOVE_DETAIL_ADD_MOVE_REFERENCE_HPP_CU_ONCE_

#include <phalanx/config.hpp.cu>

#include <boost/mpl/or.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/placeholders.hpp>

#include <phalanx/move/detail/rvalue.hpp.cu>
#include <phalanx/move/detail/is_move_reference.hpp.cu>

#include <phalanx/utility/identity.hpp.cu>
#include <phalanx/utility/apply_if.hpp.cu>

#include <phalanx/type_traits/add_const.hpp.cu>
#include <phalanx/type_traits/add_volatile.hpp.cu>
#include <phalanx/type_traits/is_lvalue_reference.hpp.cu>
#include <phalanx/type_traits/is_void.hpp.cu>
#include <phalanx/type_traits/is_const.hpp.cu>
#include <phalanx/type_traits/is_volatile.hpp.cu>
#include <phalanx/type_traits/remove_cv.hpp.cu>
#include <phalanx/type_traits/remove_reference.hpp.cu>

namespace phalanx
{

namespace move_detail
{

template < typename T, bool, bool const_, bool volatile_ >
struct _add_move_reference_impl
  : public lazy_apply_if_c<
      const_,
      add_const< ::boost::mpl::_1 >,
      apply_if_c<
        volatile_,
        add_volatile< ::boost::mpl::_1 >,
        rv_< T > & > > {};

template < typename T, bool const_, bool volatile_ >
struct _add_move_reference_impl< T, true, const_, volatile_ >
  : public identity< T > {};

template < typename T >
struct add_move_reference
  : public _add_move_reference_impl<
      typename ::boost::mpl::eval_if<
        is_move_reference< T >,
        identity< T >,
        remove_cv< typename remove_reference< T >::type > >::type,
      ::boost::mpl::or_<
        is_lvalue_reference< T >,
        is_void< T > >::value,
      is_const< T >::value,
      is_volatile< T >::value > {};

} // namespace move_detail

} // namespace phalanx

#endif // IG_PHALANX_MOVE_DETAIL_ADD_MOVE_REFERENCE_HPP_CU_ONCE_

